﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;

namespace Framework.Testing
{
    public class PerfTestResult
    {
        public int Iterations{get;set;}
        public long Milliseconds{get;set;}
        public long Ticks { get; set; }
        public override string ToString()
        {
            return Iterations + " iterations in " + Milliseconds + " ms, " + Ticks + " ticks";
        }
    }
    public static class PerfTester
    {

        public static PerfTestResult DoTest(Action exec, int numberOfIterations = 500, Action prepare = null, Action clean = null)
        {
            Action<bool, int> exec2 = (x, y) => exec();
            return DoTest(exec2, numberOfIterations, prepare, clean);
        }

        public static PerfTestResult DoTest(Action<int> exec, int numberOfIterations = 500, Action prepare = null, Action clean = null)
        {
            Action<bool, int> exec2 = (x, y) => exec(y);
            return DoTest(exec2, numberOfIterations, prepare, clean);
        }

        public static PerfTestResult DoTest(Action<bool, int> exec, int numberOfIterations = 500, Action prepare = null, Action clean = null)
        {
            Stopwatch stopwatch = new Stopwatch();

            long seed = System.Environment.TickCount; 	// Prevents the JIT Compiler from optimizing Fkt calls away
            Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2); // Uses the second Core or Processor for the Test
            Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;  	// Prevents "Normal" processes from interrupting Threads
            Thread.CurrentThread.Priority = ThreadPriority.Highest;  	// Prevents "Normal" Threads from interrupting this thread


            // ALGORITHM WARMUP PHASE
            if (prepare != null) prepare();
            stopwatch.Start();
            int i = 0;
            while (stopwatch.ElapsedMilliseconds < 1500)
            {
                exec(true, i);
                i++;
            }
            stopwatch.Stop(); 
            if (clean != null) clean();

            // TESTING PHASE
            if (prepare != null) prepare();
            stopwatch.Reset();
            stopwatch.Start();
            for (int x = 0; x < numberOfIterations; x++)
            {
                exec(false, x);
            }
            stopwatch.Stop();
            if (clean != null) clean();
            return new PerfTestResult { Iterations = numberOfIterations, Milliseconds = stopwatch.ElapsedMilliseconds, Ticks = stopwatch.ElapsedTicks };
        }
    }
}
